package com.zmc.lostfound.post.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zmc.lostfound.common.constant.PostConstant;
import com.zmc.lostfound.common.exception.MyException;
import com.zmc.lostfound.common.utils.PageResult;
import com.zmc.lostfound.common.utils.Result;
import com.zmc.lostfound.common.utils.redis.RedisCacheUtil;
import com.zmc.lostfound.post.dao.PostDao;
import com.zmc.lostfound.post.dao.PostReportDao;
import com.zmc.lostfound.post.entity.PostEntity;
import com.zmc.lostfound.post.entity.PostReportEntity;
import com.zmc.lostfound.post.service.PostReportService;
import com.zmc.lostfound.post.service.PostReviewService;
import com.zmc.lostfound.post.vo.PostReportQueryVO;
import com.zmc.lostfound.post.vo.PostReportSaveVO;
import com.zmc.lostfound.post.vo.PostReviewSaveVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

import static com.zmc.lostfound.common.constant.RabbitMqConstant.POST_EXCHANGE;
import static com.zmc.lostfound.common.constant.RabbitMqConstant.POST_SAVE_KEY;
import static com.zmc.lostfound.common.constant.RedisConstant.CACHE_POST_DETAIL_KEY_PREFIX;

/**
 * @author ZMC
 * @description 帖子举报业务类
 * @email 2869581855@qq.com
 * @date 2023-07-05 15:49:44
 */
@Service
public class PostReportServiceImpl extends ServiceImpl<PostReportDao, PostReportEntity> implements PostReportService {

    private final PostDao postDao;

    private final PostReviewService postReviewService;

    private final ThreadPoolExecutor threadPoolExecutor;

    private final RedisCacheUtil redisCacheUtil;

    private final RabbitTemplate rabbitTemplate;

    public PostReportServiceImpl(PostDao postDao, PostReviewService postReviewService, ThreadPoolExecutor threadPoolExecutor, RedisCacheUtil redisCacheUtil, RabbitTemplate rabbitTemplate) {
        this.postDao = postDao;
        this.postReviewService = postReviewService;
        this.threadPoolExecutor = threadPoolExecutor;
        this.redisCacheUtil = redisCacheUtil;
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 多条件查询帖子举报信息
     *
     * @param postReportQueryVO 帖子举报信息查询请求体
     * @return PageResult
     */
    @Override
    public PageResult queryPage(PostReportQueryVO postReportQueryVO) {
        Integer pageNo = postReportQueryVO.getPageNo();
        Integer pageSize = postReportQueryVO.getPageSize();
        Page<PostReportEntity> page = new Page<>(pageNo, pageSize);
        QueryWrapper<PostReportEntity> queryWrapper = new QueryWrapper<>();
        Long postId = postReportQueryVO.getPostId();
        Long fromUserId = postReportQueryVO.getFromUserId();
        Long toUserId = postReportQueryVO.getToUserId();
        Integer reportStatus = postReportQueryVO.getReportStatus();
        queryWrapper
                .eq(postId != null, "post_id", postId)
                .eq(fromUserId != null, "from_user_id", fromUserId)
                .eq(toUserId != null, "to_user_id", toUserId)
                .eq(reportStatus != null, "report_status", reportStatus)
                .orderByAsc("report_status")
                .orderByAsc("id");
        return new PageResult(this.page(page, queryWrapper));
    }

    /**
     * 按主键id查询帖子举报信息
     *
     * @param id 举报信息id
     * @return PostReportEntity
     */
    @Override
    public PostReportEntity queryInfoById(Long id) {
        if (id == null || id <= 0) {
            MyException.throwException("查询失败: 主键id不能为null且必须大于0");
        }
        return this.getById(id);
    }

    /**
     * 用户举报帖子
     *
     * @param postReportSaveVO 帖子举报信息新增/修改请求体
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result insertPostReport(PostReportSaveVO postReportSaveVO) {
        PostReportEntity postReportEntity = BeanUtil.copyProperties(postReportSaveVO, PostReportEntity.class);
        // 设置帖子举报记录的状态为 未审核
        postReportEntity.setReportStatus(PostConstant.PostReportEnum.NOT_REVIEW.getCode());
        if (!this.save(postReportEntity)) {
            MyException.throwException("举报失败");
        }
        return Result.ok("举报信息已发送到后台，请耐心等待举报结果");
    }

    /**
     * 修改帖子举报信息
     *
     * @param postReportSaveVO 帖子举报信息新增/修改请求体
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result updatePostReport(PostReportSaveVO postReportSaveVO) {
        // 1.修改举报记录的举报状态
        CompletableFuture<Void> postReportFuture = CompletableFuture.runAsync(() -> {
            PostReportEntity postReportEntity = BeanUtil.copyProperties(postReportSaveVO, PostReportEntity.class);
            if (!this.updateById(postReportEntity)) {
                MyException.throwException("举报信息修改失败");
            }
        }, threadPoolExecutor);
        // 2.如果举报成功
        Integer reportStatus = postReportSaveVO.getReportStatus();
        if (PostConstant.PostReportEnum.REPORT_SUCCESS.getCode().equals(reportStatus)) {
            CompletableFuture<Void> postFuture = CompletableFuture.runAsync(() -> {
                // 2.1将帖子状态修改为 审核不通过
                if (postDao.updateById(PostEntity.builder()
                        .id(postReportSaveVO.getPostId())
                        .reviewStatus(PostConstant.PostReviewEnum.REVIEW_FAIL.getCode())
                        .build()) <= 0) {
                    MyException.throwException("帖子审核状态修改失败");
                }
                // 2.2删除redis缓存
                redisCacheUtil.deleteByKey(CACHE_POST_DETAIL_KEY_PREFIX + postReportSaveVO.getPostId());
                // 2.3发送消息到post.topic交换机，实现MySQL与ES的数据同步
                rabbitTemplate.convertAndSend(POST_EXCHANGE, POST_SAVE_KEY, postReportSaveVO.getPostId());
            }, threadPoolExecutor);
            // 2.4新增一条审核不通过的审核记录
            CompletableFuture<Void> postReviewFuture = CompletableFuture.runAsync(() -> {
                PostReviewSaveVO postReviewSaveVO = PostReviewSaveVO.builder()
                        .postId(postReportSaveVO.getPostId())
                        .userId(postReportSaveVO.getToUserId())
                        .reviewStatus(PostConstant.PostReviewEnum.REVIEW_FAIL.getCode())
                        .description(postReportSaveVO.getDescription())
                        .build();
                postReviewService.insertPostReview(postReviewSaveVO);
            }, threadPoolExecutor);
            CompletableFuture.allOf(postFuture, postReviewFuture).join();
        }
        postReportFuture.join();
        return Result.ok("修改成功");
    }

    /**
     * 按主键id删除帖子举报信息
     *
     * @param id 举报信息id
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result deleteById(Long id) {
        if (id == null || id <= 0) {
            MyException.throwException("删除失败: 主键id不能为null且必须大于0");
        }
        this.removeById(id);
        return Result.ok("删除成功");
    }

    /**
     * 按帖子id删除帖子举报信息
     *
     * @param postId 帖子id
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result deleteBatchByPostId(Long postId) {
        if (postId == null || postId <= 0) {
            MyException.throwException("删除失败: 帖子id不能为null且必须大于0");
        }
        this.remove(new QueryWrapper<PostReportEntity>().eq("post_id", postId));
        return Result.ok("删除成功");
    }

}